delta: Add --if-not-exists option
authorColin Walters <walters@verbum.org>
Fri, 1 Jul 2016 18:39:49 +0000 (14:39 -0400)
committerAtomic Bot <atomic-devel@projectatomic.io>
Mon, 4 Jul 2016 13:27:06 +0000 (13:27 +0000)
I often want to have "idempotent" systems that iterate to a known
state.  If after generating a commit, the system is interrupted, I'd
like the next run to still generate a delta.  But we don't want to
regenerate if one exists, hence this option.

Closes: #375
Approved by: jlebon

src/libostree/ostree-cmdprivate.c
src/libostree/ostree-cmdprivate.h
src/libostree/ostree-repo-static-delta-core.c
src/libostree/ostree-repo-static-delta-private.h
src/ostree/ot-builtin-static-delta.c
tests/test-delta.sh

index 2c85bb4a09d63670083fd73301472399f518b8c9..4367b497e8c40bc38a7ed040f175785b48f919c1 100644 (file)
@@ -47,6 +47,7 @@ ostree_cmd__private__ (void)
   static OstreeCmdPrivateVTable table = {
     impl_ostree_generate_grub2_config,
     _ostree_repo_static_delta_dump,
+    _ostree_repo_static_delta_query_exists,
     _ostree_repo_static_delta_delete
   };
 
index 9a74ead19812c012844c8d38e0e6863eb5f9d01d..8d1c653e0b438d7a3804237f04e9eef0edcc7125 100644 (file)
@@ -27,6 +27,7 @@ G_BEGIN_DECLS
 typedef struct {
   gboolean (* ostree_generate_grub2_config) (OstreeSysroot *sysroot, int bootversion, int target_fd, GCancellable *cancellable, GError **error);
   gboolean (* ostree_static_delta_dump) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
+  gboolean (* ostree_static_delta_query_exists) (OstreeRepo *repo, const char *delta_id, gboolean *out_exists, GCancellable *cancellable, GError **error);
   gboolean (* ostree_static_delta_delete) (OstreeRepo *repo, const char *delta_id, GCancellable *cancellable, GError **error);
 } OstreeCmdPrivateVTable;
 
index 6253a45fc0d4983b262ba0e0264a03b04acf6e8b..b730c40fd6c6254446c0720491101ff26f1ea647 100644 (file)
@@ -819,6 +819,39 @@ _ostree_repo_static_delta_delete (OstreeRepo                    *self,
   return ret;
 }
 
+gboolean
+_ostree_repo_static_delta_query_exists (OstreeRepo                    *self,
+                                        const char                    *delta_id,
+                                        gboolean                      *out_exists,
+                                        GCancellable                  *cancellable,
+                                        GError                      **error)
+{
+  gboolean ret = FALSE;
+  g_autofree char *from = NULL; 
+  g_autofree char *to = NULL;
+  g_autofree char *superblock_path = NULL;
+  struct stat stbuf;
+
+  _ostree_parse_delta_name (delta_id, &from, &to);
+  superblock_path = _ostree_get_relative_static_delta_superblock_path (from, to);
+
+  if (fstatat (self->repo_dir_fd, superblock_path, &stbuf, 0) < 0)
+    {
+      if (errno == ENOENT)
+        {
+          *out_exists = FALSE;
+          return TRUE;
+        }
+      else
+        {
+          glnx_set_error_from_errno (error);
+          return FALSE;
+        }
+    }
+  *out_exists = TRUE;
+  return TRUE;
+}
+
 gboolean
 _ostree_repo_static_delta_dump (OstreeRepo                    *self,
                                 const char                    *delta_id,
index eeb99c3f79de53222d8a4f8cb7d98dbcb4a597a2..31e8971ee1a49eaee70a0f795fd69e4a59549c61 100644 (file)
@@ -190,6 +190,13 @@ _ostree_delta_compute_similar_objects (OstreeRepo                 *repo,
                                        GCancellable               *cancellable,
                                        GError                    **error);
 
+gboolean
+_ostree_repo_static_delta_query_exists (OstreeRepo                 *repo,
+                                        const char                 *delta_id,
+                                        gboolean                   *out_exists,
+                                        GCancellable               *cancellable,
+                                        GError                    **error);
+
 gboolean
 _ostree_repo_static_delta_dump (OstreeRepo                 *repo,
                                 const char                 *delta_id,
index 09eb90ab55471c731f1e8493047a9bdcd254c6cd..90702c5acda5cb17e5f83f554bb1bf4cd6b5f866 100644 (file)
@@ -37,6 +37,7 @@ static gboolean opt_empty;
 static gboolean opt_swap_endianness;
 static gboolean opt_inline;
 static gboolean opt_disable_bsdiff;
+static gboolean opt_if_not_exists;
 
 #define BUILTINPROTO(name) static gboolean ot_static_delta_builtin_ ## name (int argc, char **argv, GCancellable *cancellable, GError **error)
 
@@ -64,6 +65,7 @@ static GOptionEntry generate_options[] = {
   { "inline", 0, 0, G_OPTION_ARG_NONE, &opt_inline, "Inline delta parts into main delta", NULL },
   { "to", 0, 0, G_OPTION_ARG_STRING, &opt_to_rev, "Create delta to revision REV", "REV" },
   { "disable-bsdiff", 0, 0, G_OPTION_ARG_NONE, &opt_disable_bsdiff, "Disable use of bsdiff", NULL },
+  { "if-not-exists", 'n', 0, G_OPTION_ARG_NONE, &opt_if_not_exists, "Only generate if a delta does not already exist", NULL },
   { "set-endianness", 0, 0, G_OPTION_ARG_STRING, &opt_endianness, "Choose metadata endianness ('l' or 'B')", "ENDIAN" },
   { "swap-endianness", 0, 0, G_OPTION_ARG_NONE, &opt_swap_endianness, "Swap metadata endianness from host order", NULL },
   { "min-fallback-size", 0, 0, G_OPTION_ARG_STRING, &opt_min_fallback_size, "Minimum uncompressed size in megabytes for individual HTTP request", NULL},
@@ -264,6 +266,20 @@ ot_static_delta_builtin_generate (int argc, char **argv, GCancellable *cancellab
         }
       if (!ostree_repo_resolve_rev (repo, opt_to_rev, FALSE, &to_resolved, error))
         goto out;
+
+      if (opt_if_not_exists)
+        {
+          gboolean does_exist;
+          g_autofree char *delta_id = from_resolved ? g_strconcat (from_resolved, "-", to_resolved, NULL) : g_strdup (to_resolved);
+          if (!ostree_cmd__private__ ()->ostree_static_delta_query_exists (repo, delta_id, &does_exist, cancellable, error))
+            goto out;
+          if (does_exist)
+            {
+              g_print ("Delta %s already exists.\n", delta_id);
+              ret = TRUE;
+              goto out;
+            }
+        }
       
       if (opt_endianness)
         {
index 4b2b879ab6ab929adbcbae32522f7ac0a26bfb33..bd735c4a3e44ffd639aefa3e688abb67fd4ea8cf 100755 (executable)
@@ -82,6 +82,8 @@ get_assert_one_direntry_matching() {
 origrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
 
 ${CMD_PREFIX} ostree --repo=repo static-delta generate --empty --to=${origrev}
+${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --empty --to=${origrev} > out.txt
+assert_file_has_content out.txt "${origrev} already exists"
 ${CMD_PREFIX} ostree --repo=repo static-delta list | grep ${origrev} || exit 1
 ${CMD_PREFIX} ostree --repo=repo prune
 ${CMD_PREFIX} ostree --repo=repo static-delta list | grep ${origrev} || exit 1
@@ -91,7 +93,12 @@ ${CMD_PREFIX} ostree --repo=repo commit -b test -s test --tree=dir=files
 
 newrev=$(${CMD_PREFIX} ostree --repo=repo rev-parse test)
 
-${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline
+${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --from=${origrev} --to=${newrev} --inline
+${CMD_PREFIX} ostree --repo=repo static-delta generate --if-not-exists --from=${origrev} --to=${newrev} --inline > out.txt
+assert_file_has_content out.txt "${origrev}-${newrev} already exists"
+# Should regenerate
+${CMD_PREFIX} ostree --repo=repo static-delta generate --from=${origrev} --to=${newrev} --inline > out.txt
+assert_not_file_has_content out.txt "${origrev}-${newrev} already exists"
 
 deltaprefix=$(get_assert_one_direntry_matching repo/deltas '.')
 deltadir=$(get_assert_one_direntry_matching repo/deltas/${deltaprefix} '-')